package com.cehome.cloudbox.service.impl;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cehome.cloudbox.constans.Constants;
import com.cehome.cloudbox.constans.ExtensionTaskProperties;
import com.cehome.cloudbox.constans.MsgConstants;
import com.cehome.cloudbox.constans.PlMsgConstants;
import com.cehome.cloudbox.doman.dto.*;
import com.cehome.cloudbox.doman.vo.*;
import com.cehome.cloudbox.entity.Inform;
import com.cehome.cloudbox.entity.ProcBusDemo;
import com.cehome.cloudbox.entity.ProcDefExtend;
import com.cehome.cloudbox.enums.ProcCommentTypeEnum;
import com.cehome.cloudbox.enums.ProcIncStateEnum;
import com.cehome.cloudbox.exception.BizException;
import com.cehome.cloudbox.flowalbe.FlowableReturnModel;
import com.cehome.cloudbox.flowalbe.FlowableTaskService;
import com.cehome.cloudbox.mapper.ProcBusDemoMapper;
import com.cehome.cloudbox.service.IProcCommonService;
import com.cehome.cloudbox.service.IProcDefExtendService;
import com.cehome.cloudbox.service.IProcInstanceService;
import com.cehome.cloudbox.service.ProcessIntanceLastService;
import com.cehome.cloudbox.utils.UUidUtil;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.converter.BpmnXMLConverter;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.EndEvent;
import org.flowable.bpmn.model.ExtensionElement;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.common.engine.impl.identity.Authentication;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.history.HistoricProcessInstanceQuery;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.engine.task.Comment;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskInfo;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 流程实例 服务实现类
 * </p>
 */
@Service
@Slf4j
public class ProcInstanceServiceImpl implements IProcInstanceService {

    @Resource
    private IProcDefExtendService iProcDefExtendService;
    @Resource
    private IProcCommonService iProcCommonService;
    @Resource
    private RepositoryService repositoryService;
    @Resource
    private RuntimeService runtimeService;
    @Resource
    private TaskService taskService;
    @Resource
    private IdentityService identityService;
    @Resource
    private HistoryService historyService;
    @Resource
    private ProcBusDemoMapper busDemoMapper;
    @Resource
    private FlowableTaskService flowableTaskService;
    @Autowired
    private ProcessIntanceLastService processIntanceLastService;

    /**
     * 流程开始
     *
     * @param param 流程启动DTO
     * @return 流程状态DTO
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ProcStateDto start(ProcStartDto param) {
        //根据企业编号和业务类型，来获取流程扩展类
        LambdaQueryWrapper<ProcDefExtend> procDefExtendQueryWrapper = Wrappers.lambdaQuery();
        procDefExtendQueryWrapper.eq(ProcDefExtend::getOrg, param.getOrg());
        procDefExtendQueryWrapper.eq(ProcDefExtend::getType, param.getType());
        procDefExtendQueryWrapper.apply(true,"FIND_IN_SET ('"+param.getUnit()+"',unit)");
        ProcDefExtend procDefExtend = iProcDefExtendService.getOne(procDefExtendQueryWrapper);
        Map<String, Object> variables = ObjectUtil.isEmpty(param.getVariables()) ? new HashMap<>() : param.getVariables();
        if("true".equals(procDefExtend.getFirstZhihui())){
            variables.put("zhihui",param.getChaosong());
        }

        // 设置申请人
        variables.put(ExtensionTaskProperties.FLOWABLE_APPLY_USER_ID, param.getUserId());
        // 设置申请人
        Authentication.setAuthenticatedUserId(param.getUserId());
        ProcessInstance processInstance = runtimeService.startProcessInstanceById(procDefExtend.getProcDefId(),param.getBusId(),variables);
        System.out.println(processInstance);
        Task task = taskService.createTaskQuery()
                .processInstanceId(processInstance.getId())
                .active()
                .singleResult();

        // 在变量中设置流程首个任务节点
        taskService.setVariable(task.getId(), ExtensionTaskProperties.FLOWABLE_APPLY_DEFINITION_ID, task.getTaskDefinitionKey());
        // 在变量中设置流程流水单号
        taskService.setVariable(task.getId(), ExtensionTaskProperties.FLOWABLE_PROCESS_SERIAL_NO, param.getSerialNo());
        // 在变量中设置流程进行中状态
        taskService.setVariable(task.getId(), ExtensionTaskProperties.FLOWABLE_PROCESS_INSTANCE_STATE,ProcIncStateEnum.RUNNING.getState());
        // 添加意见
        iProcCommonService.addTaskHandleComment(task.getId(), task.getProcessInstanceId(),ProcCommentTypeEnum.APPLY.getType(), param.getComment(), param.getUserId());

        // 受领人
        taskService.setAssignee(task.getId(), param.getUserId());
        //给下节点的候选人形参入参
        FlowElement flowElement = flowableTaskService.getNodeByTask(task,"now");
        //获取自定义的参数信息
        Map<String, List<ExtensionElement>> extensionElements = flowElement.getExtensionElements();
        //获取下节点的自定义参数设置
        FlowableReturnModel flowableReturnModel = processIntanceLastService.getModel(flowElement.getId(),extensionElements);
        //给下级节点复制审批人
        variables.put(flowableReturnModel.getAssignListName(),param.getHuiqian());

        // 处理任务
        taskService.complete(task.getId(),variables);
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
        BpmnXMLConverter bpmnXmlConverter=new BpmnXMLConverter();
        String bpmn=new String(bpmnXmlConverter.convertToXML(bpmnModel));
        System.out.println(bpmn);
        return iProcCommonService.procIncState(task.getProcessInstanceId());
    }

    /**
     * 流程撤回
     *
     * @param param 流程实例处理DTO
     * @return 流程状态DTO
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ProcStateDto revoke(ProcInsHandleDto param) {
        List<Task> taskList = taskService.createTaskQuery()
                .processInstanceId(param.getProcInsId())
                .active()
                .list();
        if (ObjectUtil.isEmpty(taskList)) {
            log.error("任务取得失败，流程实例ID：{}", param.getProcInsId());
            throw new BizException(MsgConstants.ERR_E099);
        }

        Task task = taskList.get(0);

        // 获取上一节点任务
        HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(task.getProcessInstanceId())
                .finished()
                .orderByHistoricTaskInstanceEndTime()
                .desc()
                .list()
                .get(0);
        // 申请节点
        String applyDefId = taskService.getVariable(task.getId(), ExtensionTaskProperties.FLOWABLE_APPLY_DEFINITION_ID, String.class);
        // 判断上一节点是否是申请节点
        if (!applyDefId.equals(historicTaskInstance.getTaskDefinitionKey())) {
            log.error("当前申请已被处理，不可撤回，流程实例ID：{}", param.getProcInsId());
            throw new BizException(PlMsgConstants.ERR_ERR_PL_FLOW001);
        }
        // 添加撤回意见
        iProcCommonService.addTaskHandleComment(task.getId(), task.getProcessInstanceId(),
                ProcCommentTypeEnum.REVOKE.getType(), param.getComment(), param.getUserId());
        // 设置审批人
        taskService.setAssignee(task.getId(), param.getUserId());
        // 撤回初始节点
        List<Execution> executions = runtimeService.createExecutionQuery()
                .parentId(task.getProcessInstanceId())
                .list();
        List<String> executionIds = executions.stream().map(Execution::getId).collect(Collectors.toList());
        // 执行跳转
        runtimeService.createChangeActivityStateBuilder()
                .processInstanceId(task.getProcessInstanceId())
                .moveExecutionsToSingleActivityId(executionIds, applyDefId)
                .changeState();
        return iProcCommonService.procIncState(task.getProcessInstanceId());
    }

    /**
     * 流程终止
     *
     * @param param 流程实例处理DTO
     * @return 流程状态DTO
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ProcStateDto termination(ProcInsHandleDto param) {
        List<Task> taskList = taskService.createTaskQuery()
                .processInstanceId(param.getProcInsId())
                .active()
                .list();
        if (ObjectUtil.isEmpty(taskList)) {
            log.error("任务取得失败，流程实例ID：{}", param.getProcInsId());
            throw new BizException(MsgConstants.ERR_E099);
        }

        Task task = taskList.get(0);
        // 在变量中设置流程终止状态
        taskService.setVariable(task.getId(), ExtensionTaskProperties.FLOWABLE_PROCESS_INSTANCE_STATE,
                ProcIncStateEnum.TERMINATION.getState());
        // 添加终止意见
        String userId = "11111";
        iProcCommonService.addTaskHandleComment(task.getId(), task.getProcessInstanceId(),
                ProcCommentTypeEnum.STOP.getType(), param.getComment(), userId);
        // 设置审批人
        taskService.setAssignee(task.getId(), userId);
        // 获取bpmn对象
        BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
        // 获取结束节点
        List<EndEvent> endEventList = bpmnModel.getMainProcess().findFlowElementsOfType(EndEvent.class);
        String endDefId = endEventList.get(0).getId();
        // 撤回初始节点
        List<Execution> executions = runtimeService.createExecutionQuery()
                .parentId(task.getProcessInstanceId())
                .list();
        List<String> executionIds = executions.stream().map(Execution::getId).collect(Collectors.toList());
        // 执行跳转
        runtimeService.createChangeActivityStateBuilder()
                .processInstanceId(task.getProcessInstanceId())
                .moveExecutionsToSingleActivityId(executionIds, endDefId)
                .changeState();
        return iProcCommonService.procIncState(task.getProcessInstanceId());
    }

    /**
     * 流程取消
     *
     * @param param 流程实例处理DTO
     * @return 流程状态DTO
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ProcStateDto cancel(ProcInsHandleDto param) {
        List<Task> taskList = taskService.createTaskQuery()
                .processInstanceId(param.getProcInsId())
                .active()
                .list();
        if (ObjectUtil.isEmpty(taskList)) {
            log.error("任务取得失败，流程实例ID：{}", param.getProcInsId());
            throw new BizException(MsgConstants.ERR_E099);
        }

        Task task = taskList.get(0);

        // 在变量中设置流程取消状态
        taskService.setVariable(task.getId(), ExtensionTaskProperties.FLOWABLE_PROCESS_INSTANCE_STATE,
                ProcIncStateEnum.CANCEL.getState());
        // 添加取消意见
        iProcCommonService.addTaskHandleComment(task.getId(), task.getProcessInstanceId(),
                ProcCommentTypeEnum.CANCEL.getType(), param.getComment(), param.getUserId());

        // 删除流程实例
        runtimeService.deleteProcessInstance(param.getProcInsId(), ProcCommentTypeEnum.CANCEL.getRemark());
        // // 删除历史流程实例
        // historyService.deleteHistoricProcessInstance(param.getProcInsId());
        return iProcCommonService.procIncState(task.getProcessInstanceId());
    }



    /**
     * 流程审批历史
     *
     * @param procInsId 流程实例ID
     * @return 审批历史列表
     */
    @Override
    public List<ProcHistoryDto> approvalHistory(String procInsId) {
        List<ProcHistoryDto> procHistoryDtoList = new ArrayList<>();
        // 获取意见评论内容
        List<Comment> commentList = taskService.getProcessInstanceComments(procInsId);
        if (ObjectUtil.isEmpty(commentList)) {
            return procHistoryDtoList;
        }

        // 取得处理人
        List<String> userIdList = commentList.stream()
                .map(Comment::getUserId).filter(StrUtil::isNotEmpty).distinct().collect(Collectors.toList());
//        Map<String, String> userMap = getUserMap(userIdList);

        // 获取历史任务
        List<HistoricTaskInstance> hisTaskIns = historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(procInsId)
                .finished()
                .list();
        // 获取每个任务ID对应的节点信息
        BpmnModel bpmnModel = repositoryService.getBpmnModel(hisTaskIns.get(0).getProcessDefinitionId());
        Map<String, FlowElement> flowElementMap = hisTaskIns.stream().collect(Collectors.toMap(
                TaskInfo::getId,
                item -> bpmnModel.getFlowElement(item.getTaskDefinitionKey()),
                (oldVal, newVal) -> oldVal));

        // 按时间倒序排序
        List<Comment> commentSortList = commentList.stream().sorted(Comparator.comparing(Comment::getTime).reversed()).collect(Collectors.toList());
        ProcHistoryDto procHistoryDto;
        FlowElement flowElement;
        for (Comment comment : commentSortList) {
            procHistoryDto = new ProcHistoryDto();
            procHistoryDto.setTaskId(comment.getTaskId());
            flowElement = flowElementMap.get(comment.getTaskId());
            if (ObjectUtil.isNotEmpty(flowElement)) {
                procHistoryDto.setTaskDefId(flowElement.getId());
                procHistoryDto.setTaskDefName(flowElement.getName());//节点名称、、
            }
            procHistoryDto.setProcInsId(comment.getProcessInstanceId());
            procHistoryDto.setType(comment.getType());
            procHistoryDto.setTypeName(ProcCommentTypeEnum.getRemarkByType(comment.getType()));
            procHistoryDto.setComment(comment.getFullMessage());
            procHistoryDto.setUserId(comment.getUserId());
//            procHistoryDto.setUserName(userMap.get(comment.getUserId()));
            procHistoryDto.setOperateTime(comment.getTime());
            procHistoryDtoList.add(procHistoryDto);
        }

        return procHistoryDtoList;
    }




    /**
     * 流程审批历史
     *
     * @param busId 业务id
     * @return 审批历史列表
     */
    @Override
    public List<ProcHistoryDto> getApprovalHistory(String busId) {
        List<HistoricProcessInstance> historicProcessInstanceList = historyService.createHistoricProcessInstanceQuery()
                .processInstanceBusinessKey(busId)
                .orderByProcessInstanceStartTime()
                .desc()
                .list();
        List<ProcHistoryDto> procHistoryDtoList = new ArrayList<>();
        // 获取意见评论内容
        List<Comment> commentList = taskService.getProcessInstanceComments(historicProcessInstanceList.get(0).getId());
        if (ObjectUtil.isEmpty(commentList)) {
            return procHistoryDtoList;
        }

        // 取得处理人
        List<String> userIdList = commentList.stream()
                .map(Comment::getUserId).filter(StrUtil::isNotEmpty).distinct().collect(Collectors.toList());
//        Map<String, String> userMap = getUserMap(userIdList);

        // 获取历史任务
        List<HistoricTaskInstance> hisTaskIns = historyService.createHistoricTaskInstanceQuery()
                .processInstanceBusinessKey(busId)
                .finished()
                .list();
        // 获取每个任务ID对应的节点信息
        BpmnModel bpmnModel = repositoryService.getBpmnModel(hisTaskIns.get(0).getProcessDefinitionId());
        Map<String, FlowElement> flowElementMap = hisTaskIns.stream().collect(Collectors.toMap(
                TaskInfo::getId,
                item -> bpmnModel.getFlowElement(item.getTaskDefinitionKey()),
                (oldVal, newVal) -> oldVal));

        // 按时间倒序排序
        List<Comment> commentSortList = commentList.stream().sorted(Comparator.comparing(Comment::getTime).reversed()).collect(Collectors.toList());
        ProcHistoryDto procHistoryDto;
        FlowElement flowElement;
        for (Comment comment : commentSortList) {
            procHistoryDto = new ProcHistoryDto();
            procHistoryDto.setTaskId(comment.getTaskId());
            flowElement = flowElementMap.get(comment.getTaskId());
            if (ObjectUtil.isNotEmpty(flowElement)) {
                procHistoryDto.setTaskDefId(flowElement.getId());
                procHistoryDto.setTaskDefName(flowElement.getName());
            }
            procHistoryDto.setProcInsId(comment.getProcessInstanceId());
            procHistoryDto.setType(comment.getType());
            procHistoryDto.setTypeName(ProcCommentTypeEnum.getRemarkByType(comment.getType()));
            procHistoryDto.setComment(comment.getFullMessage());
            procHistoryDto.setUserId(comment.getUserId());
//            procHistoryDto.setUserName(userMap.get(comment.getUserId()));
            procHistoryDto.setOperateTime(comment.getTime());
            procHistoryDtoList.add(procHistoryDto);
        }

        return procHistoryDtoList;
    }

    /**
     * 获取流程图
     *
     * @param procInsId 流程实例ID
     * @return 流程图DTO
     */
//    @Override
//    public ProcDiagramDto diagram(String procInsId) {
//        // 获取历史流程实例
//        HistoricProcessInstance hisProcIns = historyService.createHistoricProcessInstanceQuery()
//                .processInstanceId(procInsId)
//                .singleResult();
//        if (ObjectUtil.isEmpty(hisProcIns)) {
//            log.error("流程实例取得失败，流程实例ID：{}", procInsId);
//            throw new BizException(MsgConstants.ERR_E099);
//        }
//
//        ProcDiagramDto procDiagramDto = new ProcDiagramDto();
//        procDiagramDto.setProcInsId(procInsId);
//        // 流程模板数据
//        InputStream is = repositoryService.getResourceAsStream(hisProcIns.getDeploymentId(),
//                hisProcIns.getProcessDefinitionKey() + BPMN_FILE_SUFFIX);
//        procDiagramDto.setBpmnXml(IoUtil.readUtf8(is));
//
//        // 获取活动任务
//        List<Task> taskList = taskService.createTaskQuery()
//                .includeProcessVariables()
//                .processInstanceId(procInsId)
//                .active().list();
//        if (ObjectUtil.isNotEmpty(taskList)) {
//            procDiagramDto.setNewTaskDefId(taskList.get(0).getTaskDefinitionKey());
//
//            // 获取申请节点
//            String applyDefId = Convert.toStr(taskList.get(0).getProcessVariables().get(ExtensionTaskProperties.FLOWABLE_APPLY_DEFINITION_ID));
//            // 如果活动节点为申请节点 则不需要获取历史审批历史节点
//            if (applyDefId.equals(taskList.get(0).getTaskDefinitionKey())) {
//                return procDiagramDto;
//            }
//        }
//
//        // 获取所有履历
//        List<Comment> commentList = taskService.getProcessInstanceComments(procInsId);
//        // 获取最后申请节点时间
//        Comment comment = commentList.stream()
//                .filter(com -> ProcCommentTypeEnum.APPLY.getType().equals(com.getType()))
//                .max(Comparator.comparing(Comment::getTime)).get();
//        // 获取最后申请后的履历
//        List<Comment> lastApplyCommentList = commentList.stream()
//                .filter(com -> DateUtil.compare(com.getTime(), comment.getTime()) >= 0
//                        && !CommentEntity.TYPE_EVENT.equals(com.getType())).collect(Collectors.toList());
//        Map<String, String> lastApplyCommentMap = lastApplyCommentList
//                .stream().collect(Collectors.toMap(Comment::getTaskId, Comment::getUserId, (var1, var2) -> var1));
//
//        // 获取用户信息Map
//        List<String> userId = lastApplyCommentList.stream().map(Comment::getUserId)
//                .filter(StrUtil::isNotEmpty).distinct().collect(Collectors.toList());
////        Map<String, String> userMap = getUserMap(userId);
//        // 获取历史活动节点
//        List<HistoricActivityInstance> hisActInsList = historyService.createHistoricActivityInstanceQuery()
//                .processInstanceId(procInsId)
//                .finished()
//                .orderByHistoricActivityInstanceStartTime()
//                .asc()
//                .list();
//
//        // 按照节点定义ID合并用户名
//        Map<String, List<String>> taskDefIdMap = new LinkedHashMap<>();
//        String userName;
//        for (HistoricActivityInstance hisActIns : hisActInsList) {
////            userName = userMap.get(lastApplyCommentMap.get(hisActIns.getTaskId()));
////            if (taskDefIdMap.containsKey(hisActIns.getActivityId())) {
////                if (ObjectUtil.isNotEmpty(userName)) {
////                    taskDefIdMap.get(hisActIns.getActivityId()).add(userName);
////                }
////            } else {
////                if (ObjectUtil.isEmpty(userName)) {
////                    taskDefIdMap.put(hisActIns.getActivityId(), new ArrayList<>());
////                } else {
////                    taskDefIdMap.put(hisActIns.getActivityId(), ListUtil.toList(userName));
////                }
////            }
//        }
//
//        // MAP转List
//        List<ProcHisTaskDto> procHisTaskDtoList = taskDefIdMap.entrySet().stream()
//                .map(et -> new ProcHisTaskDto(et.getKey(), et.getValue())).collect(Collectors.toList());
//
//        procDiagramDto.setProcHisTaskDtoList(procHisTaskDtoList);
//
//        return procDiagramDto;
//    }

    /**
     * 流程实例分页查询
     *
     * @param param 流程实例分页查询VO
     * @return 流程实例分页列表
     */
    @Override
    public Page<ProcInsPageShowVo> page(ProcInsPageQueryVo param) {
        HistoricProcessInstanceQuery processInstanceQuery = historyService.createHistoricProcessInstanceQuery()
                .includeProcessVariables()
                .orderByProcessInstanceStartTime()
                .desc();
        // 流程编码
        if (StrUtil.isNotEmpty(param.getProcDefCode())) {
            processInstanceQuery.processDefinitionKey(param.getProcDefCode());
        }
        // 流水单号
        if (StrUtil.isNotEmpty(param.getProcSerialNo())) {
            processInstanceQuery.variableValueEqualsIgnoreCase(ExtensionTaskProperties.FLOWABLE_PROCESS_SERIAL_NO,
                    Constants.WILDCARD + param.getProcSerialNo() + Constants.WILDCARD);
        }
        // 流程实例状态
        if (StrUtil.isNotEmpty(param.getProcInsState())) {
            processInstanceQuery.variableValueEquals(ExtensionTaskProperties.FLOWABLE_PROCESS_INSTANCE_STATE, param.getProcInsState());
        }
        Page<ProcInsPageShowVo> page = new Page<>(param.getCurrent(), param.getPageSize(), processInstanceQuery.count());
        List<HistoricProcessInstance> hisProcInsList = processInstanceQuery.listPage(param.getCurrent() - 1, param.getPageSize());
        if (ObjectUtil.isEmpty(hisProcInsList)) {
            return page;
        }

        // 获取流程编码对应流程类型Map
        List<String> procDefCodeList = hisProcInsList.stream()
                .map(HistoricProcessInstance::getProcessDefinitionKey).distinct().collect(Collectors.toList());

        // 获取活动的任务信息
        List<String> activeProcInsIdSet =
                hisProcInsList.stream().filter(ins -> ObjectUtil.isEmpty(ins.getEndTime())).map(HistoricProcessInstance::getId).collect(Collectors.toList());
        Map<String, String> activeTaskMap = new HashMap<>();
        if (ObjectUtil.isNotEmpty(activeProcInsIdSet)) {
            List<Task> activeTaskList = taskService.createTaskQuery().processInstanceIdIn(activeProcInsIdSet).active().list();
            activeTaskMap = activeTaskList.stream().collect(Collectors.toMap(TaskInfo::getProcessInstanceId, TaskInfo::getId, (var1, var2) -> var1));
        }

        // 获取人员信息
//        Map<String, String> userMap = getUserMap(
//                hisProcInsList.stream().map(HistoricProcessInstance::getStartUserId).distinct().collect(Collectors.toList()));

        // 编辑
        List<ProcInsPageShowVo> procInsPageShowVoList = new ArrayList<>();
        ProcInsPageShowVo procInsPageShowVo;
        for (HistoricProcessInstance hisProcIns : hisProcInsList) {
            // 流程定义相关信息
            procInsPageShowVo = new ProcInsPageShowVo();
            procInsPageShowVo.setProcDefId(hisProcIns.getProcessDefinitionId());
            procInsPageShowVo.setProcDefName(hisProcIns.getProcessDefinitionName());
            procInsPageShowVo.setProcDefCode(hisProcIns.getProcessDefinitionKey());
            // 流程实例相关信息
            procInsPageShowVo.setProcInsId(hisProcIns.getId());

            // 设定流水单号
            procInsPageShowVo.setProcSerialNo(Convert.toStr(hisProcIns.getProcessVariables()
                    .get(ExtensionTaskProperties.FLOWABLE_PROCESS_SERIAL_NO)));
            procInsPageShowVo.setBusId(hisProcIns.getBusinessKey());
            // 设定发起人等信息
            procInsPageShowVo.setStartUserId(hisProcIns.getStartUserId());
//            procInsPageShowVo.setStartUserName(userMap.get(procInsPageShowVo.getStartUserId()));
            procInsPageShowVo.setStartTime(hisProcIns.getStartTime());
            procInsPageShowVo.setEndTime(hisProcIns.getEndTime());
            // 流程状态
            procInsPageShowVo.setProcInsState(Convert.toStr(hisProcIns.getProcessVariables()
                    .get(ExtensionTaskProperties.FLOWABLE_PROCESS_INSTANCE_STATE)));
            // 任务相关信息
            procInsPageShowVo.setActiveTaskId(activeTaskMap.get(procInsPageShowVo.getProcInsId()));
            procInsPageShowVoList.add(procInsPageShowVo);
        }

        page.setRecords(procInsPageShowVoList);
        return page;
    }

    /**
     * 我发起的流程分页查询
     *
     * @param param 流程实例分页查询VO
     * @return 我发起的流程分页列表
     */
    @Override
    public Page<ProcMyProcPageShowVo> myProcess(ProcInsPageQueryVo param) {
        String userId = "11111";
        HistoricProcessInstanceQuery processInstanceQuery = historyService.createHistoricProcessInstanceQuery()
                .includeProcessVariables()
                .startedBy(userId)
                .orderByProcessInstanceStartTime()
                .desc();
        // 流程编码
        if (StrUtil.isNotEmpty(param.getProcDefCode())) {
            processInstanceQuery.processDefinitionKey(param.getProcDefCode());
        }
        // 流水单号
        if (StrUtil.isNotEmpty(param.getProcSerialNo())) {
            processInstanceQuery.variableValueLikeIgnoreCase(ExtensionTaskProperties.FLOWABLE_PROCESS_SERIAL_NO,
                    Constants.WILDCARD + param.getProcSerialNo() + Constants.WILDCARD);
        }
        // 流程实例状态
        if (StrUtil.isNotEmpty(param.getProcInsState())) {
            processInstanceQuery.variableValueEquals(ExtensionTaskProperties.FLOWABLE_PROCESS_INSTANCE_STATE, param.getProcInsState());
        }
        Page<ProcMyProcPageShowVo> page = new Page<>(param.getCurrent(), param.getPageSize(), processInstanceQuery.count());
        List<HistoricProcessInstance> hisProcInsList = processInstanceQuery.listPage((param.getCurrent() - 1)*param.getPageSize(), param.getPageSize());
        if (ObjectUtil.isEmpty(hisProcInsList)) {
            return page;
        }

        // 获取流程编码对应流程类型Map
        List<String> procDefCodeList = hisProcInsList.stream()
                .map(HistoricProcessInstance::getProcessDefinitionKey).distinct().collect(Collectors.toList());

        // 获取活动的任务信息
        List<String> activeProcInsIdSet =
                hisProcInsList.stream().filter(ins -> ObjectUtil.isEmpty(ins.getEndTime())).map(HistoricProcessInstance::getId).collect(Collectors.toList());
        List<Task> activeTaskList = new ArrayList<>();
        if (ObjectUtil.isNotEmpty(activeProcInsIdSet)) {
            activeTaskList = taskService.createTaskQuery().processInstanceIdIn(activeProcInsIdSet).active().list();
        }

        // 编辑
        List<ProcMyProcPageShowVo> myProcPageShowVoList = new ArrayList<>();
        ProcMyProcPageShowVo myProcPageShowVo;
        for (HistoricProcessInstance hisProcIns : hisProcInsList) {
            // 流程定义相关信息
            myProcPageShowVo = new ProcMyProcPageShowVo();
            myProcPageShowVo.setProcDefId(hisProcIns.getProcessDefinitionId());
            myProcPageShowVo.setProcDefName(hisProcIns.getProcessDefinitionName());
            myProcPageShowVo.setProcDefCode(hisProcIns.getProcessDefinitionKey());
            // 流程实例相关信息
            myProcPageShowVo.setProcInsId(hisProcIns.getId());
            // 设定流水单号
            myProcPageShowVo.setProcSerialNo(Convert.toStr(hisProcIns.getProcessVariables()
                    .get(ExtensionTaskProperties.FLOWABLE_PROCESS_SERIAL_NO)));
            myProcPageShowVo.setBusId(hisProcIns.getBusinessKey());
            // 设定发起人等信息
            myProcPageShowVo.setStartUserId(hisProcIns.getStartUserId());
            myProcPageShowVo.setStartTime(hisProcIns.getStartTime());
            myProcPageShowVo.setEndTime(hisProcIns.getEndTime());

            // 流程状态
            myProcPageShowVo.setProcInsState(Convert.toStr(hisProcIns.getProcessVariables()
                    .get(ExtensionTaskProperties.FLOWABLE_PROCESS_INSTANCE_STATE)));

            if (ProcIncStateEnum.RUNNING.getState().equals(myProcPageShowVo.getProcInsState())) {
                // 申请节点ID
                String applyDefId = Convert.toStr(hisProcIns.getProcessVariables().get(ExtensionTaskProperties.FLOWABLE_APPLY_DEFINITION_ID));
                // 标识数据是否可撤回
                myProcPageShowVo.setRevokeFlg(getRevokeFlg(hisProcIns.getId(), applyDefId));
                // 编辑标识数据是否可再申请或流程取消
                editApplyFlg(hisProcIns.getId(), applyDefId, activeTaskList, myProcPageShowVo);
            }
            myProcPageShowVoList.add(myProcPageShowVo);
        }

        page.setRecords(myProcPageShowVoList);
        return page;
    }

    /**
     * 获取流程实例状态和下一任务ID
     *
     * @param procInsId 流程实例ID
     * @return 流程实例状态和下一任务ID
     */
    @Override
    public ProcStateVo stateAndNextTaskId(String procInsId) {
        ProcStateVo procStateVo = new ProcStateVo();
        // 查看流程实例是否完成
        HistoricProcessInstance hisProcIns = historyService.createHistoricProcessInstanceQuery()
                .includeProcessVariables()
                .processInstanceId(procInsId)
                .singleResult();

        if (ObjectUtil.isEmpty(hisProcIns) || StrUtil.isEmpty(hisProcIns.getId())) {
            return procStateVo;
        }

        procStateVo.setProcInsId(procInsId);
        // 流程状态
        procStateVo.setProcInsState(
                Convert.toStr(hisProcIns.getProcessVariables().get(ExtensionTaskProperties.FLOWABLE_PROCESS_INSTANCE_STATE)));

        if (ProcIncStateEnum.RUNNING.getState().equals(procStateVo.getProcInsState())) {
            // 获取下一节点任务
            List<Task> nextTaskList = taskService.createTaskQuery()
                    .processInstanceId(procInsId)
                    .list();
            if (ObjectUtil.isNotEmpty(nextTaskList)) {
                procStateVo.setNextTaskId(nextTaskList.get(0).getId());
            }
        }

        return procStateVo;
    }

    /**
     * 编辑标识数据是否可再申请或流程取消
     *
     * @param procInsId  流程定义ID
     * @param applyDefId 流程申请节点ID
     * @param taskList   活动任务集合
     */
    private void editApplyFlg(String procInsId, String applyDefId, List<Task> taskList, ProcMyProcPageShowVo myProcPageShowVo) {
        // 当前流程对应的下一任务
        List<Task> nextTaskList = taskList.stream().filter(
                task -> procInsId.equals(task.getProcessInstanceId())).collect(Collectors.toList());

        boolean applyFlg = false;
        if (ObjectUtil.isNotEmpty(nextTaskList)) {
            // 申请节点与下一任务的节点相同时，代表此任务可做再申请和流程取消
            applyFlg = applyDefId.equals(nextTaskList.get(0).getTaskDefinitionKey());
        }

        myProcPageShowVo.setApplyFlg(applyFlg);

        // 标识数据是再申请时设置下一任务ID
        if (applyFlg) {
            myProcPageShowVo.setTaskId(nextTaskList.get(0).getId());
        }

    }

    /**
     * 标识数据是否可撤回
     *
     * @param procInsId  流程定义ID
     * @param applyDefId 流程申请节点ID
     * @return true/false
     */
    private boolean getRevokeFlg(String procInsId, String applyDefId) {

        // 获取上一节点任务
        HistoricTaskInstance hisTaskIns = historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(procInsId)
                .finished()
                .orderByHistoricTaskInstanceEndTime()
                .desc()
                .list()
                .get(0);

        // 申请节点和上一节点任务节点相同时，表示此流程可撤回
        return applyDefId.equals(hisTaskIns.getTaskDefinitionKey());
    }

}
